package com.zzgele.qmzb.api.utils;

import com.alibaba.fastjson.JSONObject;
import com.zzgele.qmzb.api.bean.WechatInfoBean;
import com.zzgele.qmzb.api.core.Constants;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * Created by Martin on 2017-08-28.
 */
public class WechatAuthUtil {
    private static Boolean isLocalDebug = false; //是否强制本地调试

    private static final Logger logger = LoggerFactory.getLogger(WechatAuthUtil.class);

    private static final String WX_AUTH_LOGIN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
    private static final String WX_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo";

    //appid和appSecret 是在公众平台上申请的
    //AppId
    private static final String WX_APP_ID = Constants.WECHAT_OPEN_APPID;
    //AppSecret
    private static final String WX_APP_SECRET = Constants.WECHAT_OPEN_APPSECRET;

    public static WechatInfoBean getWechatInfo(String code)
    {
        //获取授权 access_token
        StringBuffer loginUrl = new StringBuffer();
        loginUrl.append(WX_AUTH_LOGIN_URL).append("?appid=")
                .append(WX_APP_ID).append("&secret=")
                .append(WX_APP_SECRET).append("&code=").append(code)
                .append("&grant_type=authorization_code");
        String loginRet = WechatAuthUtil.get(loginUrl.toString());
        if(isLocalDebug) {
            loginRet = "{\"access_token\":\"HZU-b259C2azGj1yilNUbn-gFgGWQ11M9P7Sl6laDupQwocRdlxPwNEKiU6aTk4ay8A-YQyhY"
                    + "-0QkTepjY9g82I47BFNPNTFTbCckG-8G-4\",\"expires_in\":7200,"
                    + "\"refresh_token\":\"nk-7nGhYTxJT63GcxjZPlwQWcQRM7"
                    + "-1nxqJvCfQzxS8GGuUzCDmqRb0diHg4R_LMkijlmdcKFWjV1N-zQyOpczpWtDVbohLFGoyCbKKsSdo\","
                    + "\"openid\":\"oeJDl0sFPrfpO_a8Le-IroQtLv9g\",\"scope\":\"snsapi_userinfo\","
                    + "\"unionid\":\"ori6M04ykA1YymZtYH1ukPZVMmnY\"}";
        }

        JSONObject grantObj = JSONObject.parseObject(loginRet);
        String errcode = grantObj.getString("errcode");
        if (!StringUtil.isEmpty(errcode))
        {
            logger.error("login weixin error" + loginRet);
            return null;
        }
        String openId = grantObj.getString("openid");
        if (StringUtil.isEmpty(openId))
        {
            logger.error("login weixin getOpenId error" + loginRet);
            return null;
        }

        String accessToken = grantObj.getString("access_token");
        String expiresIn = grantObj.getString("expires_in");
        String refreshToken = grantObj.getString("refresh_token");
        String scope = grantObj.getString("scope");

        //获取用户信息
        StringBuffer userUrl = new StringBuffer();
        userUrl.append(WX_USER_INFO_URL).append("?access_token=").append(accessToken).append("&openid=").append(openId);
        String userRet = WechatAuthUtil.get(userUrl.toString());
        if(isLocalDebug) {
            userRet = "{\"openid\":\"oeJDl0sFPrfpO_a8Le-IroQtLv9g\",\"nickname\":\"大神\",\"sex\":1,"
                    + "\"language\":\"zh_CN\",\"city\":\"\",\"province\":\"Beijing\",\"country\":\"CN\","
                    + "\"headimgurl\":\"http:\\/\\/wx.qlogo"
                    + ".cn\\/mmopen\\/ibyLKU79PIGOI7HQXVthpWTLibL4jSajlvdOTImeLwYDU7ibKFRsF7lhgbQcOkbGxawRkniaZibQtia0WPVHRndPEKyibS4x1VPtk8N\\/0\",\"privilege\":[],\"unionid\":\"ori6M04ykA1YymZtYH1ukPZVMmnY\"}";
        }
        JSONObject userObj = JSONObject.parseObject(userRet);

        errcode = userObj.getString("errcode");
        if (!StringUtil.isEmpty(errcode))
        {
            logger.error("weixin getInfo error" + userRet);
            return null;
        }
        String nickname = userObj.getString("nickname");
        if (StringUtil.isEmpty(nickname))
        {
            logger.error("weixin getNickname error" + userRet);
            return null;
        }

        WechatInfoBean userInfo = new WechatInfoBean();
        userInfo.setOpenid(openId);
        userInfo.setAccesstoken(accessToken);
        userInfo.setRefreshtoken(refreshToken);
        userInfo.setScope(scope);
        userInfo.setExpiresin(Integer.valueOf(expiresIn));

        //String nickname = userObj.getString("nickname");
        String sex = userObj.getString("sex");
        String userImg = userObj.getString("headimgurl");
        String unionid = userObj.getString("unionid");
        userInfo.setNickname(nickname);
        userInfo.setHeadimgurl(userImg);
        userInfo.setSex(Integer.valueOf(sex));
        userInfo.setUnionid(unionid);
        return userInfo;
    }

    //TODO:Move to a single util class
    private static String get(String url) {
        String body = null;
        try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
            logger.info("create httppost:" + url);
            HttpGet get = new HttpGet(url);
            get.addHeader("Accept-Charset","utf-8");
            HttpResponse response = sendRequest(httpClient, get);
            body = parseResponse(response);
        } catch (IOException e) {
            logger.error("send post request failed: {}", e.getMessage());
        }

        return body;
    }

    private static String paramsToString(Map<String, String> params) {
        StringBuilder sb = new StringBuilder();
        try{
            for (String key : params.keySet()) {
                sb.append(String.format("&%s=%s", key, URLEncoder.encode(params.get(key), StandardCharsets.UTF_8.toString())));
            }
        }catch(UnsupportedEncodingException e){
            logger.warn("{}: encode url parameters failed", e.getMessage());
        }
        return sb.length() > 0 ? "?".concat(sb.substring(1)) : "";
    }

    private static HttpResponse sendRequest(CloseableHttpClient httpclient, HttpUriRequest httpost)
            throws ClientProtocolException, IOException {
        HttpResponse response = null;
        response = httpclient.execute(httpost);
        return response;
    }

    private static String parseResponse(HttpResponse response) {
        logger.info("get response from http server..");
        HttpEntity entity = response.getEntity();

        logger.info("response status: " + response.getStatusLine());
        Charset charset = ContentType.getOrDefault(entity).getCharset();
        if (charset != null) {
            logger.info(charset.name());
        }

        String body = null;
        try {
            body = EntityUtils.toString(entity, "utf-8");
            logger.info("body " + body);
        } catch (IOException e) {
            logger.warn("{}: cannot parse the entity", e.getMessage());
        }

        return body;
    }
}
